package cn.wenxin_zhang.smart4j.plus.proxy;

import cn.wenxin_zhang.smart4j.plus.annotation.Transaction;
import cn.wenxin_zhang.smart4j.plus.utils.DBUtils;
import net.sf.cglib.proxy.MethodProxy;
import org.apache.commons.dbutils.DbUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * Created by Wenxin on 2017/3/10.
 */
public class TransactionAspect extends LifeCycleAspectAdapter {

    private static Logger logger = LoggerFactory.getLogger(TransactionAspect.class);

    private Connection conn;

    public TransactionAspect() {
    }

    @Override
    protected void begin(Class<?> targetClass, Method method, Object[] params) {
        if (logger.isDebugEnabled()) {
            logger.debug("-------------------------------transaction begin-----------------------------------");
        }
    }

    @Override
    protected void before(Class<?> targetClass, Method method, Object[] params) {
        try {
            conn = DBUtils.getConnection();
            conn.setAutoCommit(false);
        } catch (Exception e) {
            logger.debug("get connection or set auto commit failure", e);
        }
    }

    @Override
    protected boolean intercept(Class<?> cls, Method method, Object[] params) throws Throwable {
        return method.isAnnotationPresent(Transaction.class);
    }

    @Override
    protected void after(Class<?> targetClass, Method method, Object[] params) throws Exception {
        try {
            conn.commit();
            DbUtils.close(conn);
            conn = null;
        } catch (Exception e) {
            logger.debug("close connection failure", e);
            throw e;
        }
    }

    @Override
    protected void error(Class<?> targetClass, Method method, Object[] params, Exception e) throws Exception {
        if (e instanceof RuntimeException) {
            conn.rollback();
            logger.debug("transaction rollback", e);
        }
        throw e;
    }

    @Override
    protected void end(Class<?> targetClass, Method method, Object[] params) throws Exception {
        try {
            DbUtils.close(conn);
            conn = null;
        } catch (Exception e) {
            logger.debug("close connection failure", e);
            throw e;
        }
        if (logger.isDebugEnabled()) {
            logger.debug("-------------------------------transaction end-------------------------------------");
        }
    }
}
